#!/usr/bin/python3

""" Parse lcov info file """

import sys
import re
import json


def obj2json(obj, indent=2):
    return json.dumps(obj, indent=indent)


def get_src_file_relative_path(src_file_path):
    ret = re.search(r'/linux-\d+\.\d+\.\d+-', src_file_path)
    if ret is None:
        return None  # INVALID-SOURCE-FILE

    start, _ = ret.span()
    target_path = src_file_path[start:]
    plist = target_path.split('/')
    return '/'.join(plist[2:])


def filter(block_lines):
    case = None
    src_file = None
    total_lines = 0
    hit_lines = 0
    for line in block_lines:
        if line.startswith('TN:'):
            case = line.split(':')[-1]
            continue

        if line.startswith('SF:'):
            src_file = get_src_file_relative_path(line.split(':')[-1])
            continue

        if line.startswith('LF:'):
            total_lines = int(line.split(':')[-1])
            continue

        if line.startswith('LH:'):
            hit_lines = int(line.split(':')[-1])
            continue

    out = dict()
    out['case'] = case
    out['src_file'] = src_file
    out['total_lines'] = total_lines
    out['hit_lines'] = hit_lines
    out['cov'] = float('%.3f' % (hit_lines / total_lines))
    return out


def parse(file_handle):
    """
    For the fields of lcov info file, please refer to:
    o https://blog.csdn.net/vivasoft/article/details/8330186
    """

    block_start = 'TN:'
    block_end = 'end_of_record'

    blocks = []
    while True:
        line = file_handle.readline()
        if not line:
            break

        line = line.strip().rstrip()
        if line.strip().startswith(block_start):
            loop_flag = True
            block = []
            block.append(line)
            continue

        if line.strip().startswith(block_end):
            loop_flag = False
            block.append(line)
            blocks.append(block)
            continue

        if loop_flag:
            block.append(line)
    return blocks


def main(argc, argv):
    if argc != 4:
        print(f'Usage: {argv[0]} <lcov info file> <case> <threshold>',
              file=sys.stderr)
        print(f'e.g.', file=sys.stderr)
        print(f'       {argv[0]} /tmp/kcovcomb_sanitized.info foo 0.90',
              file=sys.stderr)
        return 1

    lcov_info_file = argv[1]
    target_case = argv[2]
    threshold = float(argv[3])

    blocks = None
    with open(lcov_info_file, 'r') as file_handle:
        blocks = parse(file_handle)

    target_blocks = []
    for block in blocks:
        out = filter(block)

        if not out['case']:
            continue

        if out['case'].find(target_case) == -1:
            continue

        if out['cov'] >= threshold:
            target_blocks.append(out)
    print(obj2json(target_blocks), file=sys.stderr)

    for block in target_blocks:
        #
        # XXX: We print block['cov'] * 1000 because we'd like to use
        #      shell command 'sort -r'
        #
        print('%04d\t%.1f%%\t%s' % (block['cov'] * 1000,
                                    block['cov'] * 100,
                                    block['src_file']))
    return 0


if __name__ == '__main__':
    sys.exit(main(len(sys.argv), sys.argv))
